from django.db import models

class Tag(models.Model):
    name = models.CharField(max_length=200, unique=True)
    related_tags = models.ManyToManyField('self', blank=True, symmetrical=False, through='Tag_Relation')

    def rec_lookup(self, f, st):
        for obj in f():
            st.add(obj)          
            obj.rec_lookup(getattr(obj, f.__name__), st)

    def sub_types(self):
        return set([rel.source for rel in self.source_relation_set.all() if rel.is_a])

    def super_types(self):
        return set([rel.target for rel in self.target_relation_set.all() if rel.is_a])

    def sub_objects(self):
        return set([rel.target for rel in self.target_relation_set.all() if rel.has_a])

    def super_objects(self):
        return set([rel.source for rel in self.source_relation_set.all() if rel.has_a])

    def has_related_tags(self):
        return self.sub_types or self.super_types or self.sub_objects or self.super_objects

    def rec_sub_types(self):
        st = set([])
        self.rec_lookup(self.sub_types, st)
        return st

    def rec_super_types(self):
        st = set([])
        self.rec_lookup(self.super_types, st)
        return st

    def rec_sub_objects(self):
        st = set([])
        self.rec_lookup(self.sub_objects, st)
        return st

    def rec_super_objects(self):
        st = set([])
        self.rec_lookup(self.super_objects, st)
        return st

    def all_related_tags(self):
        return self.rec_sub_types() | self.rec_super_types() | self.rec_sub_objects() | self.rec_super_objects()

    def add_sub_type(self, sub_type):
        return Tag_Relation(source=sub_type, target=self, is_a=True)

    def add_super_type(self, super_type):
        return Tag_Relation(source=self, target=super_type, is_a=True)

    def add_sub_object(self, sub_object):
        return Tag_Relation(source=self, target=sub_object, has_a=True)
    
    def add_super_object(self, super_object):
        return Tag_Relation(source=super_object, target=self, has_a=True)

    def __unicode__(self):
        return self.name

class Tag_Relation(models.Model):
    source = models.ForeignKey(Tag, related_name='target_relation_set')
    target = models.ForeignKey(Tag, related_name='source_relation_set')
    is_a = models.BooleanField(default=False); # True if source is a target
    has_a = models.BooleanField(default=False); # True if source has a target
 
    class Meta:
        unique_together = ("source", "target")

    def __unicode__(self):
        if self.is_a:
            return self.source.name + " is a type of " + self.target.name
        elif self.has_a:
            return self.source.name + " consists of " + self.target.name
        else:
            return "error"
